/*
 * Copyright (C) 2018 Piotr Wittchen
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.github.pwittchen.reactivenetwork.library.rx2.internet.observing;

import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.error.DefaultErrorHandler;
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.error.ErrorHandler;
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.strategy.WalledGardenInternetObservingStrategy;
import java.net.HttpURLConnection;

/**
 * Contains state of internet connectivity settings.
 * We should use its Builder for creating new settings
 */
@SuppressWarnings("PMD") // I want to have the same method names as variable names on purpose
public final class InternetObservingSettings {
    private final int initialInterval;
    private final int interval;
    private final String host;
    private final int port;
    private final int timeout;
    private final int httpResponse;
    private final ErrorHandler errorHandler;
    private final InternetObservingStrategy strategy;

    private InternetObservingSettings(
        int initialInterval,
        int interval,
        String host,
        int port,
        int timeout,
        int httpResponse,
        ErrorHandler errorHandler,
        InternetObservingStrategy strategy) {
        this.initialInterval = initialInterval;
        this.interval = interval;
        this.host = host;
        this.port = port;
        this.timeout = timeout;
        this.httpResponse = httpResponse;
        this.errorHandler = errorHandler;
        this.strategy = strategy;
    }

    private InternetObservingSettings(Builder builder) {
        this(
            builder.initialInterval,
            builder.interval,
            builder.host,
            builder.port,
            builder.timeout,
            builder.httpResponse,
            builder.errorHandler,
            builder.strategy);
    }

    private InternetObservingSettings() {
        this(builder());
    }

    /**
     * Creates InternetObservingSettings object
     *
     * @return settings with default parameters
     */
    public static InternetObservingSettings create() {
        return new Builder().build();
    }

    /**
     * Creates builder object
     *
     * @return Builder
     */
    public static Builder builder() {
        return new Builder();
    }

    /**
     * Getter for initialInterval.
     *
     * @return initial ping interval in milliseconds
     */
    public int initialInterval() {
        return initialInterval;
    }

    /**
     * Getter for interval.
     *
     * @return ping interval in milliseconds
     */
    public int interval() {
        return interval;
    }

    /**
     * Getter for host.
     *
     * @return ping host
     */
    public String host() {
        return host;
    }

    /**
     * Getter for port.
     *
     * @return ping port
     */
    public int port() {
        return port;
    }

    /**
     * Getter for timeout.
     *
     * @return ping timeout in milliseconds
     */
    public int timeout() {
        return timeout;
    }

    /**
     * httpResponse
     *
     * @return int
     */
    public int httpResponse() {
        return httpResponse;
    }

    /**
     * Getter for errorHandler.
     *
     * @return error handler for pings and connections
     */
    public ErrorHandler errorHandler() {
        return errorHandler;
    }

    /**
     * Getter for InternetObservingStrategy.
     *
     * @return internet observing strategy
     */
    public InternetObservingStrategy strategy() {
        return strategy;
    }

    /**
     * Settings builder, which contains default parameters
     */
    public static final class Builder {
        private static final int DEFAULT_INTERVAL = 2000;
        private static final int DEFAULT_PORT = 80;
        private static final int DEFAULT_TIMEOUT = 2000;

        private int initialInterval = 0;
        private int interval = DEFAULT_INTERVAL;
        private String host = "http://clients3.google.com/generate_204";
        private int port = DEFAULT_PORT;
        private int timeout = DEFAULT_TIMEOUT;
        private int httpResponse = HttpURLConnection.HTTP_NO_CONTENT;
        private ErrorHandler errorHandler = new DefaultErrorHandler();
        private InternetObservingStrategy strategy = new WalledGardenInternetObservingStrategy();

        private Builder() {
            /* Do nothing */
        }

        /**
         * sets initial ping interval in milliseconds
         *
         * @param initialIntervalTime in milliseconds
         * @return Builder
         */
        public Builder initialInterval(int initialIntervalTime) {
            this.initialInterval = initialIntervalTime;
            return this;
        }

        /**
         * sets ping interval in milliseconds
         *
         * @param intervalTime in milliseconds
         * @return Builder
         */
        public Builder interval(int intervalTime) {
            this.interval = intervalTime;
            return this;
        }

        /**
         * sets ping host
         *
         * @param inputHost ping host
         * @return Builder
         */
        public Builder host(String inputHost) {
            this.host = inputHost;
            return this;
        }

        /**
         * sets ping port
         *
         * @param inputPort ping port
         * @return Builder
         */
        public Builder port(int inputPort) {
            this.port = inputPort;
            return this;
        }

        /**
         * sets ping timeout in milliseconds
         *
         * @param inputTimeout in milliseconds
         * @return Builder
         */
        public Builder timeout(int inputTimeout) {
            this.timeout = inputTimeout;
            return this;
        }

        /**
         * sets HTTP response code indicating that connection is established
         *
         * @param inputHttpResponse as integer
         * @return Builder
         */
        public Builder httpResponse(final int inputHttpResponse) {
            this.httpResponse = inputHttpResponse;
            return this;
        }

        /**
         * sets error handler for pings and connections
         *
         * @param inputErrorHandler error handler for pings and connections
         * @return Builder
         */
        public Builder errorHandler(ErrorHandler inputErrorHandler) {
            this.errorHandler = inputErrorHandler;
            return this;
        }

        /**
         * sets internet observing strategy
         *
         * @param observingStrategy for observing and internet connection
         * @return Builder
         */
        public Builder strategy(InternetObservingStrategy observingStrategy) {
            this.strategy = observingStrategy;
            return this;
        }

        public InternetObservingSettings build() {
            return new InternetObservingSettings(this);
        }
    }
}
